Skip to content

feat(plugin): add API-key Kiro provider - #4816

Open
wangyedev wants to merge 20 commits into
router-for-me:devfrom
wangyedev:codex/kiro-provider-upstream
Open

feat(plugin): add API-key Kiro provider#4816
wangyedev wants to merge 20 commits into
router-for-me:devfrom
wangyedev:codex/kiro-provider-upstream

Conversation

@wangyedev

Copy link
Copy Markdown

Summary

  • add an API-key-only Kiro provider as a Go dynamic plugin
  • discover entitled Kiro models per credential with caching and safe fallback behavior
  • translate Claude-native messages, tools, tool results, images, system instructions, and inference settings into the Kiro conversation protocol
  • decode Kiro AWS EventStream responses into Claude JSON/SSE
  • add plugin-executor usage publication for non-streaming and streaming billing records
  • handle complete multi-line SSE frames returned by executor plugins
  • document configuration, Podman builds, credentials, model discovery, validation scenarios, limitations, and Kiro-Go provenance

Why

CLIProxyAPI's plugin architecture can support Kiro without adding a built-in provider or duplicating the host's credential selection, session affinity, cooldown, proxy, logging, and protocol-routing infrastructure. The plugin keeps the integration isolated and uses the host HTTP bridge for outbound requests.

API keys can be referenced through api_key_env, so the resolved value does not need to be written into an auth JSON file.

Request flow

  1. The plugin recognizes auth records whose type is kiro.
  2. It discovers and registers the models available to that credential.
  3. CLIProxyAPI performs its normal auth selection and routing.
  4. The plugin converts the Claude-native request into Kiro conversation state.
  5. The host HTTP bridge sends the request to the regional Kiro runtime.
  6. The plugin validates and decodes AWS EventStream frames and returns Claude JSON or SSE.
  7. The plugin host records upstream token usage for billing.

Contribution-policy note

This PR targets dev and does not modify internal/translator/**.

Complete non-streaming OpenAI Chat Completions and Responses compatibility needs a small maintainer-owned translator change. It is tracked in #4815 with an isolated reference patch, as required by the repository's translator path guard. Claude /v1/messages is supported directly by this PR.

Validation

  • go test ./...
  • go test ./... in examples/plugin/kiro/go
  • go build -o /tmp/cliproxyapi-upstream-pr-build ./cmd/server
  • gofmt on all changed Go files
  • git diff --check origin/dev...HEAD
  • credential-pattern scan of the proposed diff

Limitations

  • Kiro OAuth/device login and refresh tokens are intentionally out of scope; this uses API-key auth only.
  • The raw Kiro runtime and model-discovery protocols are not documented public model APIs and may change.
  • Model credit multipliers are not exposed because the host model registry has no corresponding field.
  • /v1/messages/count_tokens is a clearly marked local estimate.
  • Web-search server tools are not forwarded in this initial implementation.
  • Complete non-streaming OpenAI-compatible endpoint support depends on Request translator support for native Claude JSON plugin responses #4815.

Provenance

The runtime protocol implementation was informed by the MIT-licensed Kiro-Go project at revision f8f6071c9298a4266ad3e0c7e483d4a2510cbcaf. Details are included in examples/plugin/kiro/THIRD_PARTY_NOTICES.md.

@wangyedev
wangyedev marked this pull request as ready for review August 6, 2026 08:22

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: cbaa322af2

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread examples/plugin/kiro/go/translate.go Outdated
Comment thread internal/pluginhost/executor_usage.go Outdated
Comment thread examples/plugin/kiro/go/translate.go Outdated

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 8a7f826df5

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread examples/plugin/kiro/go/translate.go Outdated
Comment on lines +404 to +405
if len(payload.ConversationState.History) >= 2 && payload.ConversationState.History[0].UserInputMessage != nil && payload.ConversationState.History[1].AssistantResponseMessage != nil {
removeAt = 2

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Evict the oldest conversation turns when truncating

For an oversized conversation without a system prompt, the normal first user/assistant pair satisfies this condition, so truncation preserves that pair and starts deleting newer entries at index 2. If the first turn contains most of the data, the payload can remain above maxKiroPayloadBytes and the function still exits once four history entries remain; even when it becomes small enough, it has discarded newer context instead of the oldest turn. Distinguish the synthetic system pair from an ordinary first turn and evict complete oldest turns accordingly.

Useful? React with 👍 / 👎.

Comment thread examples/plugin/Makefile
@@ -1,4 +1,5 @@
EXAMPLES := simple model auth frontend-auth executor protocol-format request-translator request-normalizer response-translator response-normalizer thinking usage cli management-api host-callback host-callback-auth-files host-model-callback claude-web-search-router
GO_ONLY_EXAMPLES := kiro

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Rebuild Kiro when any Go source changes

Adding Kiro to this Makefile target exposes it to the existing Go pattern rule, whose prerequisites include only kiro/go/main.go and kiro/go/go.mod. Because this plugin's implementation is split across many additional .go files, editing files such as translate.go, auth.go, or executor.go after the first build leaves bin/kiro-go.so considered up to date, so make build-kiro silently serves a stale plugin. Include all package Go sources in the target dependencies.

Useful? React with 👍 / 👎.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 3390aa71a7

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +601 to +604
for _, line := range bytes.Split(payload, []byte("\n")) {
trimmed := bytes.TrimSpace(line)
if bytes.HasPrefix(trimmed, []byte("data:")) {
dataLines = append(dataLines, bytes.Clone(trimmed))

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Buffer partial SSE records before translating chunks

Executor payloads are arbitrary raw chunks rather than complete SSE records (sdk/pluginapi/types.go:900-903), but this loop treats every data: fragment in the current chunk as a complete translation unit. When a chunk ends partway through a data line after an earlier newline—for example, event: ...\ndata: {"type":—the malformed fragment is discarded by the fallback check, and the continuation in the next chunk has no data: prefix, so response content is lost whenever host-side format translation is active. Retain incomplete SSE data across chunks and translate only complete records.

Useful? React with 👍 / 👎.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: a779ef54ce

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread examples/plugin/kiro/go/protocol.go Outdated
Comment on lines +87 to +88
Temperature float64 `json:"temperature,omitempty"`
TopP float64 `json:"topP,omitempty"`

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Preserve explicit zero sampling values

When a valid Claude request specifies temperature: 0 or top_p: 0, these omitempty fields are removed while marshaling the Kiro payload, so the upstream service receives neither setting and applies its default instead of the caller's requested sampling behavior. Track field presence or use pointers so explicit zero values remain distinguishable from omitted parameters.

Useful? React with 👍 / 👎.

Comment on lines +94 to +95
default:
return coreusage.Detail{}, false

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Parse usage for Gemini plugin outputs

For a plugin executor whose native output format is gemini, this default branch causes every non-streaming response to publish a zero-token record even when it contains usageMetadata; the streaming switch below omits Gemini in the same way. This undercounts usage and billing for Gemini-native plugins despite the existing helps.ParseGeminiUsage and helps.ParseGeminiStreamUsage parsers.

Useful? React with 👍 / 👎.

Comment on lines +78 to +80
func observePluginExecutorStreamChunk(buffer *helps.StreamUsageBuffer, format sdktranslator.Format, pending, payload []byte) []byte {
pending = append(pending, payload...)
lastNewline := bytes.LastIndexByte(pending, '\n')

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Avoid buffering unsupported stream formats

When a plugin uses a custom or otherwise unsupported output format and emits chunks without newline bytes, this append retains a duplicate of the entire stream until completion even though observePluginExecutorStreamUsage has no parser for that format. Since executor chunks are arbitrary raw payloads, a long custom-format stream can therefore consume memory proportional to the complete response; bypass line buffering for formats with no usage parser.

Useful? React with 👍 / 👎.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 3d78574e4d

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +661 to +665
var dataLines [][]byte
for _, line := range bytes.Split(payload, []byte("\n")) {
trimmed := bytes.TrimSpace(line)
if bytes.HasPrefix(trimmed, []byte("data:")) {
dataLines = append(dataLines, bytes.Clone(trimmed))

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Reassemble multi-line SSE data before translation

Even with the new record buffer supplying a complete SSE event, this loop sends every data: field to the protocol translator independently. SSE permits an event's data to span multiple data: lines, which must be joined with newline characters; a pretty-printed JSON event is therefore split into individually invalid fragments and discarded by the fallback check, losing response content whenever host-side format translation is active.

Useful? React with 👍 / 👎.

Comment thread examples/plugin/kiro/go/translate.go Outdated
}
for {
raw, errMarshal := json.Marshal(payload)
if errMarshal != nil || len(raw) <= maxKiroPayloadBytes || len(payload.ConversationState.History) <= protected {

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Reject payloads that remain above Kiro's size cap

When the oversized content is the current user message, history is empty and this condition exits immediately while the marshaled payload still exceeds maxKiroPayloadBytes; the same happens when a protected system prompt alone exceeds the cap. Such requests are sent upstream without enforcing the plugin's declared 900 KiB limit, so they fail as opaque upstream errors rather than being reduced or rejected locally.

Useful? React with 👍 / 👎.

Comment thread examples/plugin/kiro/go/translate.go Outdated
if request.Thinking != nil {
kind := strings.ToLower(strings.TrimSpace(request.Thinking.Type))
if kind == "enabled" || kind == "adaptive" {
systemPrompt = strings.TrimSpace("<thinking_mode>enabled</thinking_mode>\n<max_thinking_length>200000</max_thinking_length>\n\n" + systemPrompt)

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Honor the requested thinking budget

For a Claude request such as thinking: {"type":"enabled","budget_tokens":1024}, the request struct discards budget_tokens and this translation always tells Kiro to allow 200,000. The provider can consequently spend far more of the response budget on reasoning than the caller requested; carry the canonical budget through the provider translation instead of replacing it with a constant.

AGENTS.md reference: AGENTS.md:L29-L29

Useful? React with 👍 / 👎.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 0521c4cf75

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

switch format {
case sdktranslator.FormatClaude:
detail, ok := helps.ParseClaudeStreamUsage(line)
buffer.Observe(detail, ok)

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Preserve earlier Claude usage fields across SSE events

When a Claude-native plugin emits input and cache counts in message_start but only output_tokens in the final message_delta, this Observe call replaces the earlier detail with the output-only detail because StreamUsageBuffer keeps the latest observation. The resulting billing record loses all input and cache tokens; merge fields from successive Claude usage events instead of treating each partial usage object as a complete replacement.

Useful? React with 👍 / 👎.

Comment thread internal/pluginhost/executor_usage.go Outdated
}

func observePluginExecutorStreamUsage(buffer *helps.StreamUsageBuffer, format sdktranslator.Format, payload []byte) {
for _, line := range bytes.Split(payload, []byte("\n")) {

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Reassemble multi-line SSE data before parsing usage

When a plugin encodes a usage JSON object across multiple legal SSE data: fields, this loop sends each physical line independently to the JSON usage parser, so every fragment is invalid and the request is recorded with zero tokens. Reassemble all data: fields in each complete SSE event, as the response-translation path now does, before parsing its usage payload.

Useful? React with 👍 / 👎.

Comment thread examples/plugin/kiro/go/translate.go Outdated
if input == nil {
input = map[string]any{}
}
tools = append(tools, kiroToolUse{ToolUseID: id, Name: sanitizeToolName(name), Input: input})

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Apply tool-name disambiguation to assistant history

When two valid tool names sanitize to the same value—for example foo and foo_convertTools exposes them as foo and foo_2, but historical assistant calls of foo_ are converted here to plain foo. Kiro therefore receives history claiming that the first tool produced the second tool's call/result, which can corrupt subsequent tool selection; translate historical names through the same original-to-disambiguated mapping used for the declarations.

Useful? React with 👍 / 👎.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 893017d920

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

if strings.HasPrefix(strings.ToLower(tool.Type), "web_search") {
continue
}
name := uniqueToolName(sanitizeToolName(tool.Name), used)

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Reserve every emitted tool name globally

When distinct valid tool names sanitize into a generated suffix that is itself another tool's base name—for example foo, foo_, and foo_2—this produces foo, foo_2, and foo_2. Kiro then receives duplicate tool declarations, while nameMap["foo_2"] is overwritten, so calls may be rejected or mapped back to the wrong Claude tool; uniqueness must be checked against all emitted names, not only the counter for each sanitized base.

Useful? React with 👍 / 👎.

Comment thread examples/plugin/kiro/go/translate.go Outdated
}
payload.ConversationState.CurrentMessage.UserInputMessage = current
payload.ConversationState.History = trimLeadingAssistant(history)
payload.EstimatedInputTokens = estimateClaudeRequestInputTokens(&request)

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Recalculate usage after truncating history

For requests whose old history is removed to satisfy the 900 KiB payload cap, this estimate is calculated from the original Claude request before truncatePayload mutates the outgoing history. If Kiro omits explicit token counts and a context-usage event, responseAccumulator.finish publishes this stale value in the Claude response and the host billing record, potentially charging for hundreds of thousands of tokens that were never sent upstream; derive the fallback estimate from the retained payload after truncation.

Useful? React with 👍 / 👎.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 7bb800a840

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread examples/plugin/kiro/go/response.go Outdated
Comment on lines +27 to +31
case "reasoningContentEvent":
if text := firstStringField(event.Payload, "text", "content"); text != "" {
block := claudeContentBlock{Type: "thinking", Thinking: text}
a.appendFragment(block)
return []claudeContentBlock{block}, nil

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Emit protocol-valid signatures for thinking blocks

When Kiro returns a reasoningContentEvent, this creates an Anthropic thinking block without the required signature; the streaming writer likewise emits thinking_delta events but never a signature_delta. Clients that validate Claude responses or replay thinking blocks during a subsequent tool/user turn therefore receive unusable reasoning state. Supply a protocol-compatible signature or avoid exposing unsigned reasoning as a Claude thinking block.

Useful? React with 👍 / 👎.

Comment on lines +631 to +635
if index := bytes.Index(payload, []byte("\n\n")); index >= 0 {
end = index + 2
}
if index := bytes.Index(payload, []byte("\r\n\r\n")); index >= 0 && (end < 0 || index+4 < end) {
end = index + 4

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Recognize CR-only SSE record delimiters

For a plugin that emits valid SSE using carriage-return line endings, this record scanner never finds the \r\r blank-line delimiter and buffers the entire stream until close. The translation path then receives all CR-delimited events as one payload and typically drops them as an untranslated fallback, while usage parsing also misses the records. Recognize CR-only separators in addition to LF and CRLF.

Useful? React with 👍 / 👎.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: b9e9dd1165

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread examples/plugin/kiro/go/eventstream.go Outdated
*candidates = append(*candidates, nested)
}
}
collectUsageMaps(child, candidates)

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Limit usage scanning to provider metadata

When a Kiro tool-use event supplies input as an object containing a user-controlled nested usage map, this unrestricted recursion adds that map as a token-usage candidate. Because responseAccumulator.accept runs updateUsage for every event, tool arguments such as {"usage":{"inputTokens":100000}} can overwrite the real counts returned in the Claude response and billing record; only known provider usage locations should be inspected.

Useful? React with 👍 / 👎.

Type string `json:"type,omitempty"`
BudgetTokens int `json:"budget_tokens,omitempty"`
} `json:"thinking,omitempty"`
Tools []claudeTool `json:"tools,omitempty"`

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Preserve Claude tool_choice constraints

For a valid Claude request with tool_choice set to any, none, or a specific tool, unmarshalling into this struct silently discards the field, while all declared tools are still sent to Kiro with its default selection behavior. A caller forcing one tool can therefore receive text or a call to another tool, and a caller disabling tools can still get a tool call; translate this constraint or reject unsupported choices rather than ignoring it.

Useful? React with 👍 / 👎.

Comment thread examples/plugin/kiro/go/executor.go Outdated
Comment on lines +72 to +73
if errPrepare != nil {
return errorEnvelope("invalid_request", errPrepare.Error(), http.StatusBadRequest, false), nil

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Classify missing API keys as authentication failures

When an api_key_env variable is unset or empty, prepareUpstreamRequest fails in resolveAPIKey, but this branch—and the equivalent streaming branch—returns invalid_request with HTTP 400. This misclassifies a broken credential as a caller payload error, so clients and host auth handling cannot treat it like the 401 invalid_auth failures used elsewhere; distinguish credential-resolution errors from Claude request-validation errors.

Useful? React with 👍 / 👎.

@wangyedev
wangyedev force-pushed the codex/kiro-provider-upstream branch from b9e9dd1 to 0f4621e Compare August 7, 2026 09:43

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 0f4621e686

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread examples/plugin/kiro/go/protocol.go Outdated
Comment on lines +94 to +98
MaxTokens int `json:"max_tokens"`
Temperature *float64 `json:"temperature,omitempty"`
TopP *float64 `json:"top_p,omitempty"`
Stream bool `json:"stream,omitempty"`
System any `json:"system,omitempty"`

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Honor Claude stop sequences

For a valid Claude request containing stop_sequences, unmarshalling into this struct silently drops the field, so Kiro can continue generating past the caller's requested delimiter and report a different stop reason. Translate the sequences into the upstream inference configuration, or reject them explicitly if Kiro cannot support them.

Useful? React with 👍 / 👎.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 020f69db01

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +267 to +271
rawResponse, errCall := invokeHost(pluginabi.MethodHostHTTPDoStream, rpcHostHTTPRequest{
HostCallbackID: hostCallbackID,
Method: http.MethodPost,
URL: request.URL,
Headers: headers,

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Route callbacks through the selected auth's HTTP client

When a Kiro credential specifies proxy_url—especially direct/none to bypass a global proxy—this callback carries only the generic host callback ID, and internal/pluginhost/host_callbacks.go handles it with h.newHTTPClient(nil). Consequently both runtime requests here and model-discovery requests ignore the selected auth's proxy policy, potentially failing where Kiro is reachable only through that proxy or sending the API key through a global proxy the credential explicitly bypasses; associate these callbacks with the auth-aware HTTP client created in buildExecutorRequest.

Useful? React with 👍 / 👎.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: af3d873212

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +232 to +235
data, _ := source["data"].(string)
mediaType, _ := source["media_type"].(string)
if data == "" {
return nil

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Preserve URL-backed image inputs

When a valid Claude image block uses source: {"type":"url","url":"..."}, this reads only source.data, returns nil, and silently removes the image; an image-only prompt is consequently replaced with the "." fallback and Kiro answers without seeing the attachment. This also affects OpenAI-compatible requests because the repository's OpenAI-to-Claude translators emit URL-backed image blocks, so either fetch/forward these images or reject the unsupported source type instead of dropping it.

Useful? React with 👍 / 👎.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: f11a111bc3

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +132 to +133
if errMajor == nil && (major > 4 || major == 4 && minor >= 6) {
return 1_000_000

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Distinguish dated snapshots from minor versions

When Kiro reports only contextUsagePercentage for a dated model such as claude-opus-4-20250514, claudeVersionPattern parses 20250514 as the minor version, so this branch assumes a 1,000,000-token context instead of the model's 200,000-token context. currentInputTokens then overstates fallback input usage by 5× in both the Claude response and the host billing record; recognize date suffixes separately or derive the context limit from discovered model metadata.

Useful? React with 👍 / 👎.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: ba9e808625

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread internal/pluginhost/executor_usage.go Outdated
}

func mergeClaudePluginStreamUsage(previous, current coreusage.Detail) coreusage.Detail {
current.InputTokens = max(previous.InputTokens, current.InputTokens)

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Let final Claude usage replace provisional estimates

When a Kiro stream emits answer content before its later context/token-usage event, message_start contains EstimatedInputTokens while the final message_delta contains the authoritative count. Taking the maximum prevents that final event from correcting an overestimate, so the plugin usage reporter can overcount billing; preserve an earlier field only when the later usage object omits it rather than whenever it is smaller.

Useful? React with 👍 / 👎.

Comment on lines +27 to +31
case "reasoningContentEvent":
// Kiro does not return an Anthropic-verifiable signature. Omit its
// reasoning instead of emitting a Claude thinking block that clients
// cannot safely replay.
return nil, nil

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Count hidden reasoning in fallback usage

When Kiro emits reasoningContentEvent frames but omits explicit output-token metrics, this return discards the only representation of those generated tokens. finish() subsequently estimates output solely from the visible blocks in a.Blocks, so a request using a large thinking budget can report and bill only the short visible answer; retain enough reasoning information to include it in fallback token accounting even if unsigned reasoning cannot be exposed to the client.

Useful? React with 👍 / 👎.

Comment on lines +444 to +445
resultRaw, errCall := invokeHost(pluginabi.MethodHostHTTPDo, rpcHostHTTPRequest{
HostCallbackID: request.HostCallbackID,

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Pass the auth client through executor HTTP callbacks

When the host uses executorAdapter.HttpRequest for a Kiro credential with proxy_url, this callback still runs through a context opened by rpcPluginAdapter.HttpRequest without req.HTTPClient, so host.http.do falls back to the generic client and ignores the selected credential's proxy or direct policy. Fresh evidence beyond the earlier runtime/model-discovery report is that this separate newly added executorHTTPRequest path invokes the host callback while its RPC caller still omits the auth-aware client.

Useful? React with 👍 / 👎.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: e99dc770a9

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread docker-compose.yml Outdated
volumes:
- ${CLI_PROXY_CONFIG_PATH:-./config.yaml}:/CLIProxyAPI/config.yaml
- ${CLI_PROXY_AUTH_PATH:-./auths}:/root/.cli-proxy-api
- ${CLI_PROXY_AUTH_PATH:-./auths}:/CLIProxyAPI/auths

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Restore the Compose auth mount to the configured directory

When using the repository's default auth-dir (~/.cli-proxy-api, also shown in config.example.yaml), the process scans /root/.cli-proxy-api, but this bind mount now places the host credentials under /CLIProxyAPI/auths. Consequently a normal Compose restart makes every JSON credential in the default ./auths directory invisible and can leave the server with no available auth; either restore the /root/.cli-proxy-api destination or explicitly align auth-dir with the new mount.

Useful? React with 👍 / 👎.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant